#include "featuredeclvisitor.h"
#include "visitordata.h"

std::string validoperators[]={
"[]",
"[]:=",  //ternary
"^",
"/",
"//"
"\\\\",
"+",
"-",
"*",
"<",
">",
"<="
">=",
"=",
"/=",
"~",
"/~",
"implies",
"and then",
"or else",
"and",
"or",
"xor",
"not"    //unary
};

int validoperators_amount=24;

std::vector<std::string> FeatureDeclarationVisitor::getSignature(const Method & m)
{
 
 std::vector<std::string> result;
 for (unsigned int i=0;i<m.m_formal_args.size();i++)
	 result.push_back(m.m_formal_args[i].Type->fullName());
 return result;
}


bool equalSignatures(const std::vector<std::string>& s1, const std::vector<std::string>& s2)
{
	if (s1.size()!=s2.size())
		return false;
	for (unsigned int i=0;i<s1.size();i++)
		if (s1[i]!=s2[i])
			return false;
	return true;
}

bool FeatureDeclarationVisitor::containsSignature(const std::string & op,const std::vector<std::string> & sig)
{
	for (unsigned int i=0;i<m_operators.size();i++)
	{
		if (m_operators[i].m_operatorname==op)
		{
			std::vector<std::string> opsig=getSignature(m_methods[m_operators[i].m_methodname]);
			if (equalSignatures(opsig,sig))
				return true;
		}
	}
	return false;
}
bool FeatureDeclarationVisitor::isValidOperator(Operator & op)
{
	bool exist=false;
	for (int i=0;i<validoperators_amount;i++)
		if (op.m_operatorname==validoperators[i])
			exist=true;
	if (exist)
	{
		std::vector<std::string> sig=getSignature(m_methods[op.m_methodname]);
		unsigned int needed=1;
		if (op.m_operatorname=="not")
			needed=0;
		else 
		{
			if (op.m_operatorname=="[]:=")
				  needed=2;
		}
        if (sig.size()!=needed)
		{
			data()->add(new IncorrectOperatorSignature(currentDeclaration(),op.m_methodname,needed,sig.size()));
			exist=false;
		}
	}
	else
	{
		data()->add(new OperatorDoesNotExists(currentDeclaration(),op.m_methodname,op.m_operatorname));
	}
	return exist;
}
void FeatureDeclarationVisitor::addMethod(const std::string & s, const Method & m)
{
 if (m_methods.find(s)!=m_methods.end())
 {
	 m_data->add(new DataRedefinitionError(m.node(),m_methods[s].node(),"method",s));
 }
 else
 {
	 m_methods.insert(std::make_pair<std::string,Method>(s,m));
 }
}

void FeatureDeclarationVisitor::addField(const std::string & s, const Field & f)
{
  if (m_fields.find(s)!=m_fields.end())
  {
	  m_data->add(new DataRedefinitionError(f.node(),m_fields[s].node(),"field",s));
  }
  else
  {
	  m_fields.insert(std::make_pair<std::string,Field>(s,f));
  }
}

void  FeatureDeclarationVisitor::addOperator(const std::string & methname, 
											 const Method & m, 
											 const std::string & opname )
{
   addMethod(methname,m);
   if (m_methods.find(methname)!=m_methods.end())  //If added successfully
   {
	   Operator op(m.m_clients,m.m_classname,methname,opname);
	   if (this->isValidOperator(op))
	   {
		   std::vector<std::string> opsig=getSignature(m);
		   if (containsSignature(opname,opsig))
		   {
			   data()->add(new OperatorAlreadyDefined(m.node(),opname,opsig));
		   }
		   else
			   m_operators.push_back(op);
	   }
   }
}


void FeatureDeclaration::fillAttribute(FeatureDeclarationVisitor * visitor)
{
	visitor->setFeatureDecl(this);

	m_formal_list=linearize(m_formal_args,visitor->data());
	m_local_list=linearize(m_local_vars,visitor->data());

	std::vector<FeatureSpecName *> specs;
	if (m_specnames)
		specs=m_specnames->vector();
	for (unsigned int i=0;i<specs.size();i++)
	{
		m_decltype=specs[i]->spec();
		m_curname=specs[i]->name();
		m_curalias=specs[i]->alias();
		m_curspec=specs[i];
		m_behaviour->fillAttribute(visitor);
	}
}

void FeatureGroup::fillAttribute(FeatureDeclarationVisitor * visitor)
{
	visitor->setFeatureGroup(this);
	std::vector<std::string> clients;
    if (m_clients)
	{
		std::vector<IdentifierNode *> cls=m_clients->vector();
		for (unsigned int i=0;i<cls.size();i++)
			clients.push_back(cls[i]->data());
	}
    visitor->setClients(clients);	
	if (m_features)
	{
		std::vector<FeatureDeclaration *> decls=m_features->vector();
		for (unsigned int i=0;i<decls.size();i++)
			decls[i]->fillAttribute(visitor);
	}
}
